﻿// osgearth_tut01_A_empty_earth.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <osgViewer/Viewer>
#include <osgEarth/Notify>
#include <osgEarth/EarthManipulator>
#include <osgEarth/MapNode>
#include <osgEarth/Threading>
#include <osgEarth/ShaderGenerator>
#include <osgDB/ReadFile>
#include <osgGA/TrackballManipulator>
#include <osgUtil/Optimizer>
#include <iostream>
#include <osgEarth/Metrics>
#include <osgEarth/GDAL>
#include <osg/Group>
#include <osg/Node>
#include <osg/ShapeDrawable>
#include <osg/BlendFunc>
#include "wdirtools.h"

//imgui
#include <imgui.h>
#include <imgui_impl_opengl3.h>
#include "OsgImGuiHandler.hpp"

#include "Single8uToTex3d.h"
Single8uToTex3d g_tex3D;


using namespace osgEarth;
using namespace osgEarth::Util;
#include <string>
#include <iostream>
using namespace std;


//string g_version = "version v1.2 commit";//初步形状刻画OK
string g_version = string("version v1.3 use bluenoise");//加入蓝噪声 bluenoise  
// 实验了蓝噪声，没有生效呢，尤其是阴影区域没有生效 2025/10/01 11:01 2025/10/08 08:49


//imgui  ----------------------------------------
class ImGuiInitOperation : public osg::Operation
{
public:
	ImGuiInitOperation()
		: osg::Operation("ImGuiInitOperation", false)
	{
	}
	void operator()(osg::Object* object) override
	{
		osg::GraphicsContext* context = dynamic_cast<osg::GraphicsContext*>(object);
		if (!context)
			return;
		if (!ImGui_ImplOpenGL3_Init())
		{
			std::cout << "ImGui_ImplOpenGL3_Init() failed\n";
		}
	}
};
//IMGUI控件绘制类
class MyIMGuiHandler : public OsgImGuiHandler
{
public:
	MyIMGuiHandler() {
		_inputBuff[0] = '\0';
	}
protected:
	void drawUi() override //绘制控件
	{
		// ImGui code goes here...
		ImGui::Begin(g_version.c_str());
		//ImGui::Text(g_version.c_str());
		ImGui::Spacing();
		if (ImGui::Button("click"))
		{
			cout << "A button clicked" << endl;
		}
		ImGui::InputText("input control", _inputBuff, 127);
		ImGui::SliderFloat("slider control", &_fvalue, 0.0f, 1.0f);
		ImGui::ColorEdit4("Color", _color);
		ImGui::End();
	}
private:
	float _fvalue = 0;
	char _inputBuff[128];
	float _color[4] = { 1,1,1,1 };
};
//imgui  ---------------------------------------- end

osgViewer::Viewer* g_viewerPtr = nullptr;
float g_ftime = 0.0;
int   g_frame = 0;
class CubeUpdateCallback : public osg::NodeCallback
{
public:
	CubeUpdateCallback() {}
	virtual void operator()(osg::Node* node,osg::NodeVisitor* nv); 
};
 
void CubeUpdateCallback::operator()(osg::Node* node, osg::NodeVisitor* nv)
{
	osg::Vec3 eyePos;
	osg::Vec3 center;
	osg::Vec3 up;
	g_viewerPtr->getCamera()->getViewMatrixAsLookAt(eyePos, center, up);
	double tleft(0), tright(0), ttop(0), tbottom(0), tnear(0), tfar(0);
	g_viewerPtr->getCamera()->getProjectionMatrixAsFrustum(tleft, tright, tbottom, ttop, tnear, tfar);
	node->getOrCreateStateSet()->getUniform("eyepos")->set(eyePos);

	g_ftime += 0.1;
	node->getOrCreateStateSet()->getUniform("ftime")->set(g_ftime);
	g_frame += 1;
	node->getOrCreateStateSet()->getUniform("frame")->set(g_frame);
	//stringstream ss;
	//ss << eyePos.x() << "," << eyePos.y() << "," << eyePos.z();
	//cout << ss.str() << endl;
}



int main()
{

	osgViewer::Viewer viewer ;
	viewer.setUpViewInWindow(0, 100, 800, 600);
	viewer.setReleaseContextAtEndOfFrameHint(false);
	viewer.setCameraManipulator(new osgGA::TrackballManipulator());
	g_viewerPtr = &viewer;
	// Map is datamodel for collection of layers.
	osg::ref_ptr<osg::Group> group = new osg::Group;

	osg::ref_ptr<osg::Geode> boxGeode = new osg::Geode;

	//texture
	osg::ref_ptr<osg::Image> image = osgDB::readImageFile("opengl.png");
	osg::ref_ptr<osg::Texture2D> texture = new osg::Texture2D;
	texture->setImage(image.get());

	osg::ref_ptr<osg::Image> image2 = osgDB::readImageFile("google.png");
	osg::ref_ptr<osg::Texture2D> texture2 = new osg::Texture2D;
	texture2->setImage(image2.get());

	osg::ref_ptr<osg::Image> imageBlueNoise = osgDB::readImageFile("bluenoise3.png");
	osg::ref_ptr<osg::Texture2D> textureBlueNoise = new osg::Texture2D;
	textureBlueNoise->setFilter(osg::Texture2D::MIN_FILTER, osg::Texture2D::LINEAR);
	textureBlueNoise->setFilter(osg::Texture2D::MAG_FILTER, osg::Texture2D::LINEAR);
	textureBlueNoise->setWrap(osg::Texture3D::WRAP_T, osg::Texture3D::REPEAT); 
	textureBlueNoise->setWrap(osg::Texture3D::WRAP_S, osg::Texture3D::REPEAT); 
	textureBlueNoise->setImage(imageBlueNoise.get());

	{
		/**

		4      5


		7      6


		0      1

		3      2

		*/

		osg::ref_ptr<osg::Geometry> boxGeometry = new osg::Geometry;// geometry super is drawable.
		osg::ref_ptr<osg::DrawElementsUInt> indices = new osg::DrawElementsUInt(GL_TRIANGLES);
		//bottom xz
		indices->push_back(0); indices->push_back(1); indices->push_back(2);
		indices->push_back(0); indices->push_back(2); indices->push_back(3);
		//top xz
		indices->push_back(4); indices->push_back(6); indices->push_back(5);
		indices->push_back(4); indices->push_back(7); indices->push_back(6);
		//left -zy
		indices->push_back(0); indices->push_back(7); indices->push_back(4);
		indices->push_back(0); indices->push_back(3); indices->push_back(7);
		//left +zy
		indices->push_back(1); indices->push_back(5); indices->push_back(6);
		indices->push_back(1); indices->push_back(6); indices->push_back(2);
		//front
		indices->push_back(3); indices->push_back(6); indices->push_back(7);
		indices->push_back(3); indices->push_back(2); indices->push_back(6);
		//back
		indices->push_back(1); indices->push_back(4); indices->push_back(5);
		indices->push_back(1); indices->push_back(0); indices->push_back(4);

		osg::ref_ptr<osg::Vec3Array> vertices = new osg::Vec3Array;
		float boxSize = 100;
		vertices->push_back(osg::Vec3(-boxSize / 2, -boxSize / 2, -boxSize / 2));
		vertices->push_back(osg::Vec3(boxSize / 2, -boxSize / 2, -boxSize / 2));
		vertices->push_back(osg::Vec3(boxSize / 2, -boxSize / 2, boxSize / 2));
		vertices->push_back(osg::Vec3(-boxSize / 2, -boxSize / 2, boxSize / 2));

		vertices->push_back(osg::Vec3(-boxSize / 2, boxSize / 2, -boxSize / 2));
		vertices->push_back(osg::Vec3(boxSize / 2, boxSize / 2, -boxSize / 2));
		vertices->push_back(osg::Vec3(boxSize / 2, boxSize / 2, boxSize / 2));
		vertices->push_back(osg::Vec3(-boxSize / 2, boxSize / 2, boxSize / 2));

		boxGeometry->setVertexArray(vertices.get());
		boxGeometry->addPrimitiveSet(indices.get());
		boxGeometry->getOrCreateStateSet()->setTextureAttributeAndModes(0, texture.get(),
			osg::StateAttribute::ON);
		boxGeometry->getOrCreateStateSet()->setTextureAttributeAndModes(1, texture2.get(),
			osg::StateAttribute::ON);

		//texture3D
		g_tex3D.readSingle8uDatFile("worley3.dat",128,128,128);
		boxGeometry->getOrCreateStateSet()->setTextureAttributeAndModes(2, g_tex3D._texture3d.get(),
			osg::StateAttribute::ON);

		//blue noise texture
		boxGeometry->getOrCreateStateSet()->setTextureAttributeAndModes(3, textureBlueNoise.get(),
			osg::StateAttribute::ON);

		osg::ref_ptr<osg::Uniform> uniform = new osg::Uniform(
			"tex0", 0);
		boxGeometry->getOrCreateStateSet()->addUniform(uniform.get());
		osg::ref_ptr<osg::Uniform> uniform1 = new osg::Uniform(
			"tex1", 1);
		boxGeometry->getOrCreateStateSet()->addUniform(uniform1.get());

		osg::ref_ptr<osg::Uniform> uniformw = new osg::Uniform(
			"texw", 2);
		boxGeometry->getOrCreateStateSet()->addUniform(uniformw.get());

		osg::ref_ptr<osg::Uniform> uniformBN = new osg::Uniform(
			"texbn", 3);
		boxGeometry->getOrCreateStateSet()->addUniform(uniformBN.get());


		osg::ref_ptr<osg::Uniform> eyeUniform = new osg::Uniform("eyepos",
			osg::Vec3(0,0,0));
		boxGeometry->getOrCreateStateSet()->addUniform(eyeUniform.get());

		osg::ref_ptr<osg::Uniform> ftimeUniform = new osg::Uniform("ftime",
			g_ftime);
		boxGeometry->getOrCreateStateSet()->addUniform(ftimeUniform.get());

		osg::ref_ptr<osg::Uniform> frameUniform = new osg::Uniform("frame",
			g_frame);
		boxGeometry->getOrCreateStateSet()->addUniform(frameUniform.get());

		boxGeometry->addUpdateCallback(new CubeUpdateCallback);

		boxGeometry->getOrCreateStateSet()->setMode(GL_BLEND, osg::StateAttribute::ON);
		boxGeometry->getOrCreateStateSet()->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);

	 

		// Blending
		osg::ref_ptr<osg::BlendFunc> blendFunc = new osg::BlendFunc;
		blendFunc->setFunction(osg::BlendFunc::SRC_ALPHA, osg::BlendFunc::ONE_MINUS_SRC_ALPHA);
		boxGeometry->getOrCreateStateSet()->setAttributeAndModes(blendFunc);


		osg::ref_ptr<osg::Program> program = new osg::Program;
		{
			//shader
			string vstext, fstext;
			wDirTools::readFullTextIntoLines("vs.hlsl", vstext);
			wDirTools::readFullTextIntoLines("fs.hlsl", fstext);
			osg::ref_ptr<osg::Shader> vShader = new osg::Shader(osg::Shader::VERTEX, vstext);
			osg::ref_ptr<osg::Shader> fShader = new osg::Shader(osg::Shader::FRAGMENT, fstext);

			program->addShader(vShader.get());
			program->addShader(fShader.get());
			boxGeometry->getOrCreateStateSet()->setAttributeAndModes(program.get());
		}
		//check if getViewMatrixAsLookAt(...) on viewer camera is sufficient for your needs


		boxGeode->addDrawable(boxGeometry);
	}


	group->addChild(boxGeode);
	
	viewer.setSceneData(group);
	
	//IMGUI
	viewer.setRealizeOperation(new ImGuiInitOperation);
	//viewer.realize();
	viewer.addEventHandler(new MyIMGuiHandler);
 
	while (true) {
		 

		viewer.frame();
	}

	//imgui shutdown
	ImGui_ImplOpenGL3_Shutdown();

	ImGui::DestroyContext();

	return 0;
}
